/**
 * JimBot - Java IM Bot
 * Copyright (C) 2006-2009 JimBot project
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package ru.jimbot.modules.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ru.jimbot.table.UserPreference;

import ru.jimbot.util.Log;
import ru.jimbot.util.MainProps;

/**
 * API для JimBot Manager и любых других сторонних интерфейсов управления ботом
 * @author alex_xpert
 */
public class API extends HttpServlet {
    private String userID=""; // ИД сеанса
    private long dt = 0; // Время начала сеанса
    Class self;
    Class methodParamTypes[];
    private long lastErrLogin = 0;
    private int loginErrCount = 0;

    @Override
    public void init() throws ServletException {
    	self = getClass();
        methodParamTypes = new Class[1];
        userID = SrvUtil.getSessionId();
        try {
            methodParamTypes[0] = Class.forName("ru.jimbot.modules.http.HttpConnection");
	} catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new ServletException(e.getMessage());
	}
        Log.http("init API");
    }
    
    @Override
    public void destroy() {
        Log.http("destroy API");
    }
    
    private boolean checkSession(String id){
    	boolean f = (System.currentTimeMillis()-dt)<MainProps.getIntProperty("http.delay")*60000;
    	dt = System.currentTimeMillis();
    	return id.equals(userID) && f;
    }
    
    /**
     * Обработка введенных данных при авторизации
     * @param con
     * @throws Exception
     */
    public void login(HttpConnection con) throws IOException {
        if(loginErrCount>MainProps.getIntProperty("http.maxErrLogin"))
            if((System.currentTimeMillis()-lastErrLogin) < (60000*MainProps.getIntProperty("http.timeBlockLogin"))) return;
        String name = con.get("name");
        String pass = con.get("password");
        if (SrvUtil.getAuth(name, pass)!=1) {
            loginErrCount++;
            lastErrLogin = System.currentTimeMillis();
            if((System.currentTimeMillis()-lastErrLogin) > (60000*MainProps.getIntProperty("http.timeErrLogin"))) loginErrCount=0;
        	con.response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                con.print("Неверный логин или пароль!");
            return;
        }
        loginErrCount=0;
        userID = SrvUtil.getSessionId();
        dt = System.currentTimeMillis();
        con.addPair("uid", userID);
        getMainData(con);
    }
    
    /**
     * 
     * @param con
     * @throws IOException 
     */
    public void getMainData(HttpConnection con) throws IOException {
        String uid = con.get("uid");
        if(!checkSession(uid)) return;
        con.print("Всего сервисов: " + MainProps.getServicesCount());
    }
    
    /**
     * Возвращает основные настройки бота
     * @param con
     * @throws IOException 
     */
    public void getMainProps(HttpConnection con) throws IOException {
        String uid = con.get("uid");
        if(!checkSession(uid)) return;
        UserPreference[] up = MainProps.getUserPreference();
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for(int i=0;i<up.length;i++) {
            if(up[i].getType() != UserPreference.CATEGORY_TYPE) {
                if(first) {
                    first = false;
                } else {
                    sb.append("|");
                }
                if(up[i].getDisplayedKey().equals("")) return;
                sb.append(up[i].getKey() + ";" + up[i].getDisplayedKey() + ";" + up[i].getSaveValue());
            }
        }
        con.print(sb.toString());
    }
    
    /**
     * Устанавливает основные настройки бота
     * @param con
     * @throws IOException 
     */
    public void setMainProps(HttpConnection con) throws IOException {
        String name = con.get("name");
        String pass = con.get("password");
        if(SrvUtil.getAuth(name, pass) != 1) return;
        BufferedReader reader = con.request.getReader();
        StringBuilder sb = new StringBuilder();
        char s;
        while((s = (char) reader.read()) != '&') {
            sb.append(s);
        }
        reader.close();
        sb.delete(0, 5);
        String[] main_props = sb.toString().split("\\|");
        for(int i=0;i<main_props.length;i++) {
            String[] p = main_props[i].split(";");
            MainProps.setProperty(p[0], p.length > 1 ? p[1] : "");
        }
        MainProps.save();
    }

    /**
     * Обработчик GET запросов
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException 
     */
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    	doGetOrPost(request, response);
    }
    
    /**
     * Обработчик POST запросов
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException 
     */
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    	doGetOrPost(request, response);
    }
    
    /**
     * Обработчик GET и POST запросов
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException 
     */
    void doGetOrPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    	response.setContentType("text/html; charset=\"UTF-8\"");
    	Log.http("HTTP LOG: " + request.getRemoteAddr() + "(" + request.getRemoteHost() + ") "+ request.getQueryString());
    	HttpConnection con = new HttpConnection(request, response);
    	String page = request.getParameter("page");
    	if (page == null) {
            login(con);
    	} else {
            try {
                Method method = self.getMethod(page, methodParamTypes);
                Object methodParams[] = new Object[1];
                methodParams[0] = con;
                try {
                    method.invoke(this, methodParams);
                } catch (InvocationTargetException x) {
                    Throwable tx = x.getTargetException();
                    tx.printStackTrace();
                    SrvUtil.error(con, "Exception " + tx.getClass().getName() + ": " + tx.getMessage());
                } catch (Exception x) {
                    SrvUtil.error(con, "Exception " + x.getClass().getName() + ": " + x.getMessage());
                }
            } catch (NoSuchMethodException x) {
                SrvUtil.error(con, "No such method: " + page);
            }
        }
        con.send();
    }

}
